package com.songlanyun.common.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.Map;
import java.util.TreeMap;
@Slf4j
@Component
public class HouniaoApiUtil {

    @Value("${houniao.baseUrl:1}")
    private String baseUrl;

    @Value("${houniao.appKey:1}")
    private String appKey;

    @Value("${houniao.appSecret:1}")
    private String appSecret;

    public JSONObject client(JSONObject req, String url) {

        log.info("开始调用候鸟供应链, req:{}", JSON.toJSONString(req));
        // 拼接api公共参数
        req.put("app_key", appKey);
        req.put("version", "1.0");
        req.put("timestamp", Instant.now().getEpochSecond());
        req.put("nonce_str", "23ae8ea6701dc2427661e08e1beb4125");
        log.info("\n");
        log.info("req:");
        log.info(JSONObject.toJSONString(req));
        log.info("\n");

        // 第一步：对所有API请求参数（包括公共参数和业务参数，但除去sign参数 ），参数名称的ASCII码表的顺序排序。
        JSONObject sortedJsonObject = sortJsonObject(req);

        // 第二步：将排序好的参数（空值不参与签名）进行字符串拼接key1=value1&key2=value2&...。
        String str = jsonObjectToString(sortedJsonObject);

        // 第三步：把拼装好的 待加密串1 再拼接上appSecret
        str = str + "&" + appSecret;
        log.info("\n候鸟供应链加密签名串：\n" + str + "\n");

        // 第四步：最后对 待加密串2 进行MD5加密然后转小写，得到 签名串sign
        try {
            /*
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(str.getBytes());

            byte[] byteData = md.digest();

            // Convert the byte to hex format
            StringBuilder sb = new StringBuilder();
            for (byte b : byteData) {
                sb.append(String.format("%02x", b));
            }
            String md5Hash = sb.toString();
            *
             */
            String md5Hash = cn.hutool.crypto.digest.DigestUtil.md5Hex(str).toLowerCase();
            sortedJsonObject.put("sign", md5Hash);
        } catch (Exception e) {
            log.error(e.toString());
        }

        // 发送请求
        HttpClientUtil instance = HttpClientUtil.getInstance();
        String result = instance.sendHttpPost(baseUrl + url, sortedJsonObject.toJSONString());
        if (StringUtils.isNotBlank(result) && JSONObject.parseObject(result).getInteger("code") == 200){
            JSONObject res = JSONObject.parseObject(result);
            return res;
        } else if (JSONObject.parseObject(result).getInteger("code") != 200) {
            JSONObject res = JSONObject.parseObject(result);
            throw new RuntimeException(res.getString("code") + "-" + res.getString("msg"));
        } else {
            throw new RuntimeException("调用失败");
        }
    }

    public JSONObject sortJsonObject(JSONObject jsonObject) {
        // Use TreeMap to sort keys
        TreeMap<String, Object> sortedMap = new TreeMap<>();

        // Put all entries of the original JSONObject into the TreeMap
        for (String key : jsonObject.keySet()) {
            sortedMap.put(key, jsonObject.get(key));
        }

        // Create a new JSONObject with sorted entries
        JSONObject sortedJsonObject = new JSONObject(sortedMap);

        return sortedJsonObject;
    }

    private static String jsonObjectToString(JSONObject jsonObject) {
        // Use TreeMap to sort keys
        Map<String, Object> sortedMap = new TreeMap<>();

        // Iterate over the keys of the JSONObject and add to sortedMap
        for (String key : jsonObject.keySet()) {
            sortedMap.put(key, jsonObject.get(key));
        }

        // Build the key-value string
        StringBuilder stringBuilder = new StringBuilder();
        for (Map.Entry<String, Object> entry : sortedMap.entrySet()) {
            String paramValue = String.valueOf(entry.getValue());
            //空值不参与签名
            if(StringUtils.isNotBlank(paramValue)) {
                if (stringBuilder.length() > 0) {
                    stringBuilder.append("&");
                }
                stringBuilder.append(entry.getKey()).append("=").append(paramValue);
            }
        }

        return stringBuilder.toString();
    }
}
